package lt.vu.spf.gui;

import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.EnumSet;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.swing.JPanel;

import lt.vu.spf.graph.Edge;
import lt.vu.spf.graph.Graph;
import lt.vu.spf.graph.Vertex;

/**
 * @author Mantas Sinkevičius
 */
public class Canvas extends JPanel {
    private static final long serialVersionUID = 999473787105201615L;

    private Graph graph;
    private Set<ConfigEnum> config = EnumSet.of((ConfigEnum.SHOW_EDGE_WEIGHTS));
    private BufferedImage backgroundImage;

    public Canvas(Graph graph) {
        this.graph = graph;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setFont(new Font("SansSerif", Font.PLAIN, 9));
        drawBackgroundImageMap(g2d);
        drawVertices(g2d);
        drawEdges(g2d);
    }

    public Ellipse2D.Float buildCircle(Vertex vertex) {
        return new Ellipse2D.Float(vertex.getX() - 5, vertex.getY() - 5, 12, 12);
    }

    public Line2D.Float buildLine(Edge edge) {
        return new Line2D.Float(edge.getV1().getX(), edge.getV1().getY(), edge.getV2().getX(), edge.getV2().getY());
    }

    private void drawVertices(Graphics2D g2d) {
        for (Vertex v : graph.getVertices()) {
            g2d.setColor(Color.BLACK);
            if (v == graph.getSelectedVertex()) {
                // nustatomas pasirinktosios viršūnės žymėjimas
                g2d.setColor(Color.LIGHT_GRAY);
                g2d.fillOval(v.getX() - 14, v.getY() - 14, 30, 30);
            }
            // pakeičiamos viršūnių spalvos
            if (v == graph.getStartingVertex()) {
                g2d.setColor(Color.BLUE);
            }
            if (v == graph.getDestinationVertex()) {
                g2d.setColor(Color.RED);
            }
            if (v != graph.getStartingVertex() && v != graph.getDestinationVertex()) {
                g2d.setColor(Color.BLACK);
            }
            g2d.fill(buildCircle(v));
            if (config.contains(ConfigEnum.SHOW_VERTICES_COORDINATES)) {
                g2d.drawString(v.toString(), v.getX() + 5, v.getY() - 5);
            }
        }
    }

    private void drawEdges(Graphics2D g2d) {
        for (Edge e : graph.getEdges()) {
            // parenkama briaunos spalva
            if (e == graph.getSelectedEdge()) {
                g2d.setColor(Color.GREEN);
            } else if (e.isInShortestPath()) {
                g2d.setColor(Color.RED);
            } else {
                g2d.setColor(Color.BLACK);
            }
            // piešiama briauna
            g2d.drawLine(e.getV1().getX(), e.getV1().getY(), e.getV2().getX(), e.getV2().getY());
            // piešiamas briaunos svoris
            if (config.contains(ConfigEnum.SHOW_EDGE_WEIGHTS)) {
                g2d.drawString(e.toString(), e.getMidPoint()[0], e.getMidPoint()[1]);
            }
        }
    }

    public void loadImage(File file) {
        BufferedImage loadedImage = null;
        try {
            loadedImage = ImageIO.read(file);
            backgroundImage = loadedImage;
            repaint();
        } catch (IOException e) {
            System.out.println(e);
        }
    }

    private void drawBackgroundImageMap(Graphics2D g2d) {
        if (backgroundImage != null) {
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));
            g2d.drawImage(backgroundImage, 0, 0, null);
            g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f));
            this.setPreferredSize(new Dimension(backgroundImage.getWidth(), backgroundImage.getHeight()));
        }
    }

    public Graph getGraph() {
        return graph;
    }

    public Set<ConfigEnum> getConfig() {
        return config;
    }

    public BufferedImage getBackgroundImage() {
        return backgroundImage;
    }

    public void setBackgroundImage(BufferedImage backgroundImage) {
        this.backgroundImage = backgroundImage;
    }

}
